using DA.AnimGraph;
using OdinSerializer;
using System.Collections.Generic;
using System.Linq;

namespace DA.AnimGraph.Editor {
    internal class TimelineManager {
        Dictionary<AUID, Timeline> timelines;

        public TimelineManager(string json) {
            if (string.IsNullOrEmpty(json)) {
                timelines = new Dictionary<AUID, Timeline>();
            } else {
                byte[] dataBytes = System.Text.Encoding.UTF8.GetBytes(json);
                var timelineList = SerializationUtility.DeserializeValue<List<Timeline>>(dataBytes, DataFormat.JSON);
                timelines = new Dictionary<AUID, Timeline>(timelineList.Count);
                foreach (var timeline in timelineList) {
                    timelines.Add(timeline.uuid, timeline);
                }
            }
        }

        // 保存形式
        public string Dump() {
            var timelineList = timelines.Values.ToList();
            byte[] bytes = SerializationUtility.SerializeValue(timelineList, DataFormat.JSON);
            var json = System.Text.Encoding.UTF8.GetString(bytes);
            return json;
        }

        //public void AddTimeline(AUID uuid, Timeline timeline) {
        //    timelines.Add(uuid, timeline);
        //}

        public Timeline GetTimeline(AUID uuid) {
            if (timelines.TryGetValue(uuid, out var timeline)) {
                return timeline;
            }
            return null;
        }

        public Timeline GetTimelineOrAddDefault(AUID uuid) {
            var timeline = GetTimeline(uuid);
            if (timeline != null) {
                return timeline;
            }
            timeline = new Timeline() { uuid = uuid };
            timelines.Add(uuid, timeline);
            return timeline;
        }

        /// <summary>
        /// 复制指定timeline，返回复制后的uuid
        /// </summary>
        public AUID Duplicate(AUID uuid) {
            if (timelines.TryGetValue(uuid, out var timeline)) {
                var temp = SerializationUtility.SerializeValue(timeline, DataFormat.JSON);
                var newTimeline = SerializationUtility.DeserializeValue<Timeline>(temp, DataFormat.JSON);
                AUID newUuid = AUIDGenerator.Gen();
                newTimeline.uuid = newUuid;
                timelines.Add(newUuid, newTimeline);
                return newUuid;
            } else {
                D.W($"无法复制指定timeline，因为查找不到。 uuid: {uuid}");
                return default;
            }
        }

        /// <summary>
        /// 跨文件复制
        /// CopyToSerializeData + PasteFromSerializeData 相当于 Duplicate
        /// </summary>
        public byte[] CopyToSerializeData(AUID uuid) {
            if (timelines.TryGetValue(uuid, out var timeline)) {
                var r = SerializationUtility.SerializeValue(timeline, DataFormat.JSON);
                return r;
            } else {
                D.W($"无法复制指定timeline，因为查找不到。 uuid: {uuid}");
                return null;
            }
        }
        /// <summary>
        /// 跨文件粘贴
        /// </summary>
        public AUID PasteFromSerializeData(byte[] data) {
            var newTimeline = SerializationUtility.DeserializeValue<Timeline>(data, DataFormat.JSON);
            AUID newUuid = AUIDGenerator.Gen();
            newTimeline.uuid = newUuid;
            timelines.Add(newUuid, newTimeline);
            return newUuid;
        }

        public void RemoveTimeline(AUID uuid) {
            timelines.Remove(uuid);
        }

        public AnimGraphPublishAsset.Timeline[] Publish() {
            var outTimeline = new List<AnimGraphPublishAsset.Timeline>(timelines.Count);
            foreach (var kv in timelines) {
                if (kv.Value.events.Count == 0) {
                    continue;
                }
                var tl = new AnimGraphPublishAsset.Timeline() {
                    uuid = kv.Value.uuid,
                    events = kv.Value.events.Select(e => new AnimGraphPublishAsset.TimelineEvent() {
                        time = e.time,
                        endTime = e.endTime,
                        flag = e.flag,
                        state = e.parameter.state, // 导出的时候再获取state，因为这个值是由事件类型决定的。同时方便后期修改state定义，此时重新导出即可
                        parameter = e.parameter,
                    }).OrderBy(e => e.time).ToArray(),
                };
                outTimeline.Add(tl);
            }
            return outTimeline.ToArray();
        }

        public void ClearTimeline() {
            timelines.Clear();
        }
    }

    internal class Timeline {
        public AUID uuid;
        public List<TimelineEvent> events = new List<TimelineEvent>(); // todo:向此列表的添加应当通过TimelineManager来执行？
    }

    /// 与<see cref="AnimGraphPublishAsset.TimelineEvent"/>相比多了uuid，少了state
    public class TimelineEvent {
        public AUID uuid; // event的uuid
        public float time;
        public float endTime;
        public TimelineEventFlag flag;
        public TimelineEventParameter parameter;
    }
}
